package client

import (
	"encoding/json"
	"fmt"
	"log"
	"sync"
	"wxp2p/common"

	"github.com/pion/webrtc/v3"
)

var LocalPortSendChan = make(chan []byte)
var LocalPortRecvChan = make(chan []byte)

// server--client
func RunWebrtcAnswer(clientId string) {
	log.Println("重置连接状态-等待连接")
	done := make(chan struct{})
	closeThread1 := make(chan struct{})
	closeThread2 := make(chan struct{})

	var candidatesMux sync.Mutex
	pendingCandidates := make([]*webrtc.ICECandidate, 0)
	// Create a new RTCPeerConnection
	peerConnection, err := webrtc.NewPeerConnection(common.WebrtcConfig)
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := peerConnection.Close(); err != nil {
			fmt.Printf("cannot close peerConnection: %v\n", err)
		}
		close(closeThread1)
		close(closeThread2)
	}()

	// When an ICE candidate is available send to the other Pion instance
	// the other Pion instance will add this candidate by calling AddICECandidate
	peerConnection.OnICECandidate(func(c *webrtc.ICECandidate) {
		if c == nil {
			return
		}

		candidatesMux.Lock()
		defer candidatesMux.Unlock()
		desc := peerConnection.RemoteDescription()
		if desc == nil {
			pendingCandidates = append(pendingCandidates, c)
		} else {
			sig := common.P2PSignal{ClientId: clientId, SigType: common.ECandidate, Content: c.ToJSON().Candidate}
			P2PSignalSendChan <- sig
		}
	})

	// A HTTP handler that allows the other Pion instance to send us ICE candidates
	// This allows us to add ICE candidates faster, we don't have to wait for STUN or TURN
	// candidates which may be slower

	go func() {
		for {
			select {
			case <-closeThread1:
				return
			case sig := <-P2PSignalRecvChan:
				switch sig.SigType {
				case common.ECandidate: //另一个客户端的打洞信息，即对外暴露的外网地址
					if candidateErr := peerConnection.AddICECandidate(webrtc.ICECandidateInit{Candidate: string(sig.Content)}); candidateErr != nil {
						panic(candidateErr)
					}
				case common.ESdp: //接收另一个客户端的连接信息
					sdp := webrtc.SessionDescription{}
					json.Unmarshal([]byte(sig.Content), &sdp)
					if err := peerConnection.SetRemoteDescription(sdp); err != nil {
						panic(err)
					}

					// Create an answer to send to the other process
					answer, err := peerConnection.CreateAnswer(nil)
					if err != nil {
						panic(err)
					}
					payload, err := json.Marshal(answer)
					if err != nil {
						panic(err)
					}
					p2psig := common.P2PSignal{ClientId: clientId, SigType: common.ESdp, Content: string(payload)}
					P2PSignalSendChan <- p2psig

					// Sets the LocalDescription, and starts our UDP listeners
					err = peerConnection.SetLocalDescription(answer)
					if err != nil {
						panic(err)
					}

					candidatesMux.Lock()
					for _, c := range pendingCandidates {
						p2psig := common.P2PSignal{ClientId: clientId, SigType: common.ECandidate, Content: c.ToJSON().Candidate}
						P2PSignalSendChan <- p2psig
					}
					candidatesMux.Unlock()
				}
			}
		}
	}()

	// Set the handler for Peer connection state
	// This will notify you when the peer has connected/disconnected
	peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) {
		log.Printf("p2p连接状态改变: %s\n", s.String())
		if s == webrtc.PeerConnectionStateConnected {
			log.Println("p2p连接成功")
		}
		if s == webrtc.PeerConnectionStateFailed || s == webrtc.PeerConnectionStateDisconnected {
			// Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart.
			// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
			// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
			log.Println("p2p连接失败正在退出")
			close(done)                  //退出此线程及所有子线程
			go RunWebrtcAnswer(clientId) //重新等待连接
		}
		// if s == webrtc.PeerConnectionStateClosed {
		// 	// close(done)
		// 	// go RunWebrtcAnswer(clientId)
		// }
	})

	// Register data channel creation handling
	peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
		// Register channel opening handling
		d.OnOpen(func() {
			log.Println("p2p数据通道准备就绪")
			go func() {
				for {
					select {
					case <-closeThread2:
						// log.Println("退出子线程")
						return
					case buf := <-LocalPortSendChan:
						sendErr := d.Send(buf)
						if sendErr != nil {
							panic(sendErr)
						}
					}
				}
			}()
		})

		// Register text message handling
		d.OnMessage(func(msg webrtc.DataChannelMessage) {
			LocalPortRecvChan <- msg.Data
		})
	})

	// block
	<-done
}

func RegClientToSignalServer(clientId string) {
	// 注册个名字到服务端
	p2psig := common.P2PSignal{ClientId: clientId, SigType: common.ERegClient, Content: ""}
	P2PSignalSendChan <- p2psig
}
